import traceback
from trees import MagicMap
from context import Context

def primitive(context, name, value):
  if value.__class__==str:
    clsname='String'
  elif value.__class__==int:
    clsname='Integer'
  elif value.__class__==bool:
    clsname='Boolean'
  elif value.__class__==float:
    clsname='Float'
  elif value.__class__==list:
    clsname='List'
  elif value.__class__==dict:
    clsname='Map'
  else:
    print 'Unknown primitive class type', value.__class__, value
    raise Exception()
    return None

  cls=context.get(clsname)
  #print 'cls:', cls, clsname
  if not cls:
    print 'No cls in', context
  obj=cls.new(name, value)
  return obj

def receiver(block, r):
  print 'receiver():', r, type(r), r[0], type(r[0])
  try:
    typ=r[0]
    if typ=='self':
      slf=ArbreSelf(block)
      print 'slf:', slf
      return slf
    elif typ=='symbol':
      name=r[1]
      sym=ArbreSymbol(block, name)
      print 'sym:', sym
      return sym
    elif typ=='literal':
      value=r[1]
      print 'receiver literal:', value, type(value)
      prim=primitive(block, 'literal', value)
      print 'prim:', prim
      return prim
    else:
      print 'Unknown receiver type', typ, type(typ)
  except Exception, e:
    print 'Exception in receiver():', e
    return None

def arg(block, item):
  print 'arg():', item, type(item), item[0], type(item[0])
  try:
    typ=item[0]
    if typ=='self':
      slf=ArbreSelf(block)
      print 'slf:', slf
      return slf
    elif typ=='symbol':
      name=item[1]
      sym=ArbreSymbol(block, name)
      print 'sym:', sym
      return sym
    elif typ=='literal':
      value=item[1]
      print 'receiver literal:', value, type(value)
      prim=primitive(block, 'literal', value)
      print 'prim:', prim
      return prim
    else:
      print 'Unknown arg type', typ, type(typ)
  except Exception, e:
    print 'Exception in arg():', e
    return None

class ArbreUniverse:
  def __init__(self, map):
    self.name='Universe'
    self.locals={}

    if map:
      self.makePrimitives(map)

      for key in map.keys():
        value=map[key]
        if value.__class__==MagicMap or value.__class__==dict:
          try:
            typ=value['type']
            if typ=='module':
              self.addModule(key, value)
            elif typ=='class':
              self.locals[key]=ArbreClass(self, key, value)
            elif typ=='primitive':
              prim=self.locals[key]
              prim.update(value)
            else:
              self.locals[key]=primitive(self, key, value)
          except Exception, e:
            print 'no type', value, e
            traceback.print_exc()
            self.locals[key]=primitive(self, key, value)
        else:
          self.locals[key]=primitive(self, key, value)

  def makePrimitives(self, map):
    for key in map.keys():
      value=map[key]
      if value.__class__==dict:
        try:
          typ=value['type']
        except:
          continue
        if typ=='primitive':
          self.locals[key]=ArbrePrimitiveClass(self, key)

  def addModule(self, key, value):
    mod=ArbreModule(self, key, value)
    self.locals[key]=mod
    return mod

  def get(self, key):
    try:
      return self.locals[key]
    except:
      return None

  def __str__(self):
    return "universe("+str(self.locals.keys())+")"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'Universe'
    for key in self.locals.keys():
      value=self.locals[key]
      value.printTree(spacing+1)

class ArbreModule:
  def __init__(self, universe, name, map):
    self.universe=universe
    self.name=name
    self.locals={}

    for key in map.keys():
      value=map[key]
      #print 'adding to module: ', str(value)
      if value.__class__==MagicMap or value.__class__==dict:
        try:
          typ=value['type']
          if typ=='class':
            self.locals[key]=ArbreClass(self, key, value)
          elif typ=='primitive':
            self.locals[key]=ArbrePrimitiveClass(self, key, value)
          else:
            self.locals[key]=primitive(self, key, value)
        except:
          self.locals[key]=primitive(self, key, value)
      else:
        self.locals[key]=primitive(self, key, value)

  def get(self, key):
    try:
      return self.locals[key]
    except:
      #print str(self), 'delegating to', str(self.universe)
      try:
        return self.universe.get(key)
      except:
        return None

  def __str__(self):
    return "module["+str(self.name)+"]("+str(self.locals.keys())+")"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'Module', self.name
    for key in self.locals.keys():
      value=self.locals[key]
      value.printTree(spacing+1)

class ArbreClass:
  def __init__(self, module, name, map):
    self.module=module
    self.name=name
    self.locals={}

    try:
      parentName=map['parent']
    except:
      parentName='Object'

    self.parent=self.module.get(parentName)

    for key in map.keys():
      value=map[key]
      if value.__class__==MagicMap or value.__class__==dict:
        try:
          typ=value['type']
          if typ=='method':
            self.locals[key]=ArbreMethod(self, key, value)
          elif typ=='native':
            self.locals[key]=ArbreNativeMethod(self, key, value)
          else:
            self.locals[key]=ArbreMethod(self, key, value)
            self.locals[key]=primitive(self, key, value)
        except Exception, e:
          print 'Exception', e
          self.locals[key]=primitive(self, key, value)
      else:
        self.locals[key]=primitive(self, key, value)

  def new(self, name, instanceContext):
    return ArbreObject(self, name, instanceContext)

  def get(self, key):
    try:
      return self.locals[key]
    except:
      if self.parent:
        try:
          return self.parent.get(key)
        except:
          #print str(self), 'delegating to', str(self.module)
          try:
            return self.module.get(key)
          except:
            return None
      else:
        try:
          return self.module.get(key)
        except:
          return None

  def __str__(self):
    return "class["+str(self.module.name)+"."+str(self.name)+"]("+str(self.locals.keys())+")"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'Class', self.name
    for key in self.locals.keys():
      value=self.locals[key]
      value.printTree(spacing+1)

class ArbrePrimitiveClass:
  def __init__(self, module, name):
    self.module=module
    self.name=name
    self.parent=None
    self.locals={}

  def update(self, map):
    try:
      parentName=map['parent']
    except:
      parentName='Object'

    self.parent=self.module.get(parentName)

    for key in map.keys():
      value=map[key]
      if value.__class__==MagicMap or value.__class__==dict:
        try:
          typ=value['type']
          if typ=='method':
            self.locals[key]=ArbreMethod(self, key, value)
          elif typ=='native':
            self.locals[key]=ArbreNativeMethod(self, key, value)
          else:
            self.locals[key]=primitive(self, key, value)
        except:
          self.locals[key]=primitive(self, key, value)
      else:
        self.locals[key]=primitive(self, key, value)

  def new(self, name, value):
    if value.__class__==list:
      oldvalue=value
      value=[]
      for item in oldvalue:
        value.append(primitive(self, 'item', item))
    elif value.__class__==dict:
      oldvalue=value
      value={}
      for key in oldvalue.keys():
        item=oldvalue[key]
        value[key]=primitive(self, 'item', item)

    return ArbrePrimitiveObject(self, name, value)

  def get(self, key):
    try:
      try:
        return self.locals[key]
      except:
        if self.parent:
          #print str(self), 'delegating', key, 'to parent', str(self.module)
          try:
            return self.parent.get(key)
          except:
            #print str(self), 'delegating to', str(self.module)
            try:
              return self.module.get(key)
            except:
              #print 'no mod get'
              return None
        else:
          #print 'no parent,', str(self), 'delegating to', str(self.module)
          try:
            return self.module.get(key)
          except:
            #print 'no mod get 2'
            return None
    except Exception, e:
      print 'exception in get', e

  def __str__(self):
    return "primitiveClass["+str(self.name)+" -> "+str(self.parent)+"](: "+str(self.locals.keys())+") -> "+str(self.module)

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'PrimitiveClass', self.name
    for key in self.locals.keys():
      value=self.locals[key]
      value.printTree(spacing+1)

class ArbreObject:
  def __init__(self, cls, name, map):
    self.cls=cls
    self.name=name
    self.locals={}

    for key in map.keys():
      value=map[key]
      self.locals[key]=primitive(self, key, value)

  def get(self, key):
    try:
      return self.locals[key]
    except:
      #print str(self), 'delegating', key,'to', str(self.cls)
      try:
        return self.cls.get(key)
      except Exception, e:
        #print e
        return None

  def getMethod(self, name):
    value=self.get(name)
    methodContext=Context(Reference(self.cls.root, self.cls.path+[]), value)
    meth=ArbreMethod(self, value)

  def __str__(self):
    return "object("+str(self.name)+": "+str(self.locals.keys())+") -> "+str(self.cls)

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'Object', self.name
    for key in self.locals.keys():
      value=self.locals[key]
      value.printTree(spacing+1)

class ArbrePrimitiveObject:
  def __init__(self, cls, name, value):
    self.cls=cls
    self.name=name
    self.locals={}
    self.value=value

  def get(self, key):
    try:
      return self.locals[key]
    except:
      #print str(self), 'delegating', key, 'to', str(self.cls)
      try:
        return self.cls.get(key)
      except:
        return None

  def getValue(self):
    return self.value

  def getMethod(self, name):
    #print('object getMethod:', name)
    value=self.get(name)
    methodContext=Context(Reference(self.cls.root, self.cls.path+[]), value)
    meth=ArbreMethod(self, value)

  def __eq__(self, other):
    if other.__class__!=self.__class__:
      return False

    return self.value==other.value

  def __ne__(self, other):
    if other.__class__!=self.__class__:
      return True

    return self.value!=other.value

  def __str__(self):
#    return "primitive["+str(self.cls.name)+"]("+str(self.name)+": , "+str(self.value)+", "+str(self.locals.keys())+") -> "+str(self.cls)
    return "primitive["+str(self.cls.name)+"]("+str(self.name)+": "+str(self.value)+", "+str(self.locals.keys())+")"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, self.cls.name, self.name
    for key in self.locals.keys():
      value=self.locals[key]
      value.printTree(spacing+1)

class ArbreMethod:
  def __init__(self, obj, name, map):
    #print 'new method', obj, name, map
    self.obj=obj
    self.name=name
    self.locals={}

    code=map['code']
    print 'code:', code, map
    if not code:
      print 'No code', self.obj.name, name
    else:
      self.locals['code']=ArbreBlock(self, code)

    for key in map.keys():
      if key=='code':
        continue
      value=map[key]
      self.locals[key]=primitive(self, key, value)

  def get(self, key):
    try:
      return self.locals[key]
    except:
      #print str(self), 'delegating to', str(self.obj)
      try:
        return self.obj.get(key)
      except:
        return None

  def put(self, key, value):
    self.locals[key]=value

  def call(self, sched, args):
    t=sched.addThread(self.obj, self, args)
    return t

  def activate(self):
    return ArbreActiveMethod(self)

  def __str__(self):
#    return "method("+str(self.name)+": "+str(self.locals.keys())+") -> "+str(self.obj)
    return "method["+str(self.obj.name)+"."+str(self.name)+"]("+str(self.locals.keys())+")"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'Method', self.name
    for key in self.locals.keys():
      value=self.locals[key]
      value.printTree(spacing+1)

class ArbreNativeMethod:
  def __init__(self, obj, name, map):
    #print 'new native method', obj, name, map
    self.obj=obj
    self.name=name
    self.locals={}

    code=map['code']
    self.locals['code']=primitive(self, 'code', code)

    for key in map.keys():
      if key=='code':
        continue
      value=map[key]
      self.locals[key]=primitive(self, key, value)

  def get(self, key):
    try:
      return self.locals[key]
    except:
      #print str(self), 'delegating to', str(self.obj)
      try:
        return self.obj.get(key)
      except:
        return None

  def put(self, key, value):
    self.locals[key]=value

  def call(self, sched, args):
    t=sched.addThread(self.obj, self, args)
    return t

  def activate(self):
    return ArbreActiveMethod(self)

  def __str__(self):
#    return "method("+str(self.name)+": "+str(self.locals.keys())+") -> "+str(self.obj)
    return "method["+str(self.obj.name)+"."+str(self.name)+"]("+str(self.locals.keys())+")"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'NativeMethod', self.name
    for key in self.locals.keys():
      value=self.locals[key]
      value.printTree(spacing+1)

class ArbreActiveMethod:
  def __init__(self, method):
    self.method=method
    self.locals={}

  def get(self, key):
    try:
      return self.locals[key]
    except:
      try:
        #print str(self), 'delegating to', str(self.method)
        return self.method.get(key)
      except:
        return None

  def put(self, key, value):
    self.locals[key]=value

  def __str__(self):
#    return "active("+str(self.locals.keys())+") -> "+str(self.method)
    return "active["+str(self.method.obj.name)+"."+str(self.method.name)+"]("+str(self.locals.keys())+")"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'ActiveMethod'
    for key in self.locals.keys():
      value=self.locals[key]
      value.printTree(spacing+1)

class ArbreBlock:
  def __init__(self, context, code):
    print 'new block:', code, type(code), code[0]
    if not code:
      raise Exception('null block')
    try:
      self.context=context
      self.receiver=receiver(self, code[0])
      self.method=primitive(self, 'method', code[1])
      self.args=ArbreArgList(self, code[2])

      print 'receiver:', self.receiver
      print 'method:', self.method
      print 'args:', self.args
    except Exception, e:
      print 'Exception in new block', e
      traceback.print_exc()

  def get(self, key):
    try:
      return self.locals[key]
    except:
      try:
        #print str(self), 'delegating to', str(self.context)
        return self.context.get(key)
      except:
        return None

  def put(self, key, value):
    self.locals[key]=value

  def __str__(self):
#    return "active("+str(self.locals.keys())+") -> "+str(self.method)
     return "block"
#    return "block["+str(self.receiver)+"."+str(self.method)+"("+str(self.args)+")]"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'Block'
    self.receiver.printTree(spacing+1)
    self.method.printTree(spacing+1)
    self.args.printTree(spacing+1)

class ArbreSelf:
  def __init__(self, block):
    self.block=block
    self.name='self'

  def __str__(self):
#    return "active("+str(self.locals.keys())+") -> "+str(self.method)
    return "self"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'Self'

class ArbreSymbol:
  def __init__(self, block, name):
    self.block=block
    self.name=name

  def __str__(self):
#    return "active("+str(self.locals.keys())+") -> "+str(self.method)
    return "symbol["+str(self.name)+"]"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'Symbol', self.name

class ArbreArgList:
  def __init__(self, block, value):
    self.block=block
    self.value=[]

    for item in value:
      self.value.append(arg(block, item))

    print 'ArgList!!!:', self.value

  def __str__(self):
#    return "active("+str(self.locals.keys())+") -> "+str(self.method)
    return "args["+str(self.value)+"]"

  def __repr__(self):
    return str(self)

  def printTree(self, spacing):
    print ' '*spacing, 'Args'
    for item in self.value:
      item.printTree(spacing+1)
